#include <iostream>
#include <condition_variable>
#include <mutex>
#include <queue>
#include <thread>
#include <functional>
#include <memory>
#include <atomic>
#include <future>
#include <utility>

using func_t=std::function<void(void)>;

class ThreadPool
{
private:
    void entry()
    {
        while(!_stop)
        {
            std::vector<func_t> tmp_tasks;
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _cond.wait(lock,[this](){return _stop||!_tasks.empty();});
                tmp_tasks.swap(_tasks);//提高效率，一次唤醒，将任务全部获取，而不是一次唤醒就只获取一个任务
            }
            
            //执行任务
            for(auto& task:tmp_tasks)
            {
                task();
            }
        }
    }

public:
    ThreadPool(int thread_count=1)
        :_stop(false)
    {
        for(int i=0;i<thread_count;i++)
        {
            _threads.emplace_back(&ThreadPool::entry,this);
        }
    }

    /*
        1.有了让压入线程池的任务类型不固定，这里采用模板;函数执行的参数也由外面根据函数类型自行传入,同时也采用可变参数列表
        2.push是将packaged_task形成的shared_ptr对象压入任务池执行func函数,需要返回future类型,所以push返回值需要推导
    */
    template<class F,class ...Args>
    auto push(F&& func,Args&& ...args) -> std::future<decltype(func(args...))>
    {
        //1.推导形成构建packaged_task的返回值类型
        using res_type=decltype(func(args...));

        //2.通过bind重新生成一个无参的函数类型
        auto nfunc=std::bind(std::forward<F>(func),std::forward<Args>(args)...);

        //3.构建shared_ptr管理的packaged_task对象
        auto task=std::make_shared<std::packaged_task<res_type()>>(nfunc);

        //4.返回用于同步关联packaged_task函数返回值的future对象
        std::future<res_type> ret=task->get_future();

        //5.压入任务池
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(_stop==false) _tasks.push_back([task](){(*task)();});
        }

        //6.唤醒阻塞线程
        _cond.notify_all();
        return ret;
    }

    void stop()
    {
        if(_stop==true) return;
        _stop=true;
        _cond.notify_all();
        for(auto& iter:_threads) iter.join();
    }

    ~ThreadPool()
    {
        stop();
    }

private:
    std::atomic<bool> _stop;//原子性控制优雅退出的标志
    std::vector<func_t> _tasks;
    std::condition_variable _cond;//条件变量
    std::mutex _mutex;//互斥锁
    std::vector<std::thread> _threads;//线程池
};

int Add(int num1,int num2)
{
    return num1+num2;
}

int  main()
{
    ThreadPool pool;
    for (int i = 0; i < 10; i++) {
        std::future<int> fu = pool.push(Add, 11, i);
        std::cout << fu.get() << std::endl;
    }
    pool.stop();
    return 0;
}